﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Burraco.Library
{
    public class Partita
    {
	    private List<Coppia> coppie;
	    public TavoloDa2 TavoloDa2 { get; set; }
	    public TavoloDa3 TavoloDa3 { get; set; }
	    private List<TavoloDa4> tavoliDa4;
	    private List<ITavolo> tavoli;
	    public Torneo Torneo { get; set; }

        public delegate void TentativoFallitoEventHandler(Partita sender, TentativoFallitoEventArgs eventargs);
        public event TentativoFallitoEventHandler onTentativoFallito;
        public delegate void TavoloDa2NonValidoEventHandler(Partita sender, TavoloDa2NonValidoEventArgs eventargs);
        public event TavoloDa2NonValidoEventHandler onTavoloDa2NonValido;
        public delegate void TavoloDa3NonValidoEventHandler(Partita sender, TavoloDa3NonValidoEventArgs eventargs);
        public event TavoloDa3NonValidoEventHandler onTavoloDa3NonValido;
        public delegate void TavoloDa4NonValidoEventHandler(Partita sender, TavoloDa4NonValidoEventArgs eventargs);
        public event TavoloDa4NonValidoEventHandler onTavoloDa4NonValido;
        public delegate void TavoloDa4ValidoEventHandler(Partita sender, TavoloDa4ValidoEventArgs eventargs);
        public event TavoloDa4ValidoEventHandler onTavoloDa4Valido;
        public delegate void CoppiaValidaEventHandler(Partita sender, CoppiaValidaEventArgs eventargs);
        public event CoppiaValidaEventHandler onCoppiaValida;
        public delegate void CoppiaNonValidaEventHandler(Partita sender, CoppiaNonValidaEventArgs eventargs);
        public event CoppiaNonValidaEventHandler onCoppiaNonValida;
        public delegate void GeneraCoppieCompletatoEventHandler(Partita sender, GeneraCoppieCompletatoEventArgs eventargs);
        public event GeneraCoppieCompletatoEventHandler onGeneraCoppieCompletato;
        public delegate void GeneraTavoliCompletatoEventHandler(Partita sender, GeneraTavoliCompletatoEventArgs eventargs);
        public event GeneraTavoliCompletatoEventHandler onGeneraTavoliCompletato;

        private Random rnd;

	    public Partita(Torneo t) : this(t, new Random())
        {
	    }

        public Partita(Torneo t, Random rnd)
        {
            this.rnd = rnd;
		    Torneo = t;
		    tavoli = new List<ITavolo>();
		    tavoliDa4 = new List<TavoloDa4>();
		    coppie = new List<Coppia>();
        }

	    public List<Coppia> getListaCoppie() 
        {
		    return coppie;
	    }

        public List<ITavolo> getListaTavoli()
        {
            return tavoli;
        }

        public List<TavoloDa4> getListaTavoliDa4()
        {
            return tavoliDa4;
        }

        private bool isOkPerTavoloDa2(Giocatore g1) 
        {
		    bool blnG1OK = true;
            if ((Torneo.LimiteRipetiInTavoloZoppo > 0) || (Torneo.LimiteRipetiInTavoloZoppoDa2 > 0))
            {

		        int volteInZoppoDa2 = 0;
                foreach (Giocatore g in Torneo.getListaGiocatoriInTavoloDa2()) {
			        if (g == g1) volteInZoppoDa2++;
		        }
		
		        int volteInZoppoDa3 = 0;
                foreach (Giocatore g in Torneo.getListaGiocatoriInTavoloDa3()) {
			        if (g == g1) volteInZoppoDa3++;
		        }
		
		        blnG1OK = ((Torneo.LimiteRipetiInTavoloZoppoDa2 <= 0) || (volteInZoppoDa2 < Torneo.LimiteRipetiInTavoloZoppoDa2));
		        blnG1OK = blnG1OK && ((Torneo.LimiteRipetiInTavoloZoppo <= 0) || ((volteInZoppoDa2+volteInZoppoDa3) < Torneo.LimiteRipetiInTavoloZoppo));

            }
	
            if (TavoloDa3 != null)
            {
                for (int i = 1; i <= 3; i++)
                {
                    if (TavoloDa3.getGiocatore(i) == g1) blnG1OK = false;
                }
            }
		    
		    return blnG1OK;
	    }
	
	    private bool isOkPerTavoloDa3(Giocatore g1) 
        {
            bool blnG1OK = true;
            if ((Torneo.LimiteRipetiInTavoloZoppo > 0) || (Torneo.LimiteRipetiInTavoloZoppoDa3 > 0))
            {

                int volteInZoppoDa2 = 0;
                foreach (Giocatore g in Torneo.getListaGiocatoriInTavoloDa2())
                {
                    if (g == g1) volteInZoppoDa2++;
                }

                int volteInZoppoDa3 = 0;
                foreach (Giocatore g in Torneo.getListaGiocatoriInTavoloDa3())
                {
                    if (g == g1) volteInZoppoDa3++;
                }

                blnG1OK = ((Torneo.LimiteRipetiInTavoloZoppoDa3 <= 0) || (volteInZoppoDa3 < Torneo.LimiteRipetiInTavoloZoppoDa3));
                blnG1OK = blnG1OK && ((Torneo.LimiteRipetiInTavoloZoppo <= 0) || ((volteInZoppoDa2 + volteInZoppoDa3) < Torneo.LimiteRipetiInTavoloZoppo));
            }

            if (TavoloDa2 != null)
            {
                for (int i = 1; i <= 2; i++)
                {
                    if (TavoloDa2.getGiocatore(i) == g1) blnG1OK = false;
                }
            }

            return blnG1OK;
	    }
	
	    private void generaTavoloDa2() 
        {
		    List<Giocatore> giocatori = Torneo.getListaGiocatori();

		    int i1; Giocatore g1;
		    int i2; Giocatore g2;
		
		    bool compagni;
		    bool limiteAvversariSuperato = false; 
		    bool limiteTavoloSuperato = false; 
		
		    int timeout = 500;
		    int times = 0;

		    do {
			
			    do {
                    i1 = rnd.Next(0, giocatori.Count);
				    g1 = giocatori.ElementAt(i1);
			    } while (!isOkPerTavoloDa2(g1));
			
			
			    do {
				    do {
					    while ((i2 = rnd.Next(0, giocatori.Count)) == i1);
					    g2 = giocatori.ElementAt(i2);
				    } while ( false
					    || (Torneo.RegolaSesso == ModalitaSesso.SessoUnico && g2.Sesso != g1.Sesso)
					    || ((Torneo.RegolaSesso == ModalitaSesso.MaschiVsFemmine) && g2.Sesso == g1.Sesso)
						    );
			    } while (! isOkPerTavoloDa2(g2));

			
			    compagni = ((Torneo.RegolaCompagni == ModalitaCompagni.Mai) || (Torneo.RegolaCompagni == ModalitaCompagni.SiCoppiaNoAvversario));
			    compagni = compagni && ((g2.Compagno == g1) || (g1.Compagno == g2));
			

			    // Torneo.LimiteRipetiAvversario<=0 vuol dire nessun limite
			    if ((Torneo.LimiteRipetiAvversario > 0) || (Torneo.LimiteRipetiTavolo > 0)) {
			
				    int usataVolteAvv11 = g1.GiocaControVolte(g2);
				    int usataVolteAvv21 = g2.GiocaControVolte(g1);

				    int usataVolteTav11 = g1.GiocaControVolte(g2) + g1.GiocaAssiemeVolte(g2);
				    int usataVolteTav21 = g2.GiocaControVolte(g1) + g2.GiocaAssiemeVolte(g1);
			
			
				    int limite = Torneo.LimiteRipetiAvversario;
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv11 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv21 >= limite));

				    limite = Torneo.LimiteRipetiTavolo;
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav11 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav21 >= limite));

			    }
			
			    if (compagni || limiteAvversariSuperato || limiteTavoloSuperato) {
                    if (onTavoloDa2NonValido != null)
                    {
                        TavoloDa2NonValidoEventArgs ea = new TavoloDa2NonValidoEventArgs();
                        ea.Compagni = compagni;
                        ea.LimiteAvversariSuperato = limiteAvversariSuperato;
                        ea.LimiteTavoloSuperato = limiteTavoloSuperato;
                        ea.Giocatore1 = g1;
                        ea.Giocatore2 = g2;
                        onTavoloDa2NonValido(this, ea);
                    }
				    if (++times >= timeout) {
					    Torneo.Ricomincia();
					    return;
				    }
			    }
		    } while(compagni || limiteAvversariSuperato || limiteTavoloSuperato);
		
		    Torneo.getListaGiocatoriInTavoloDa2().Add(g1);
		    Torneo.getListaGiocatoriInTavoloDa2().Add(g2);
		    g1.AggiungiAvversari(g2);
		    g2.AggiungiAvversari(g1);
		    TavoloDa2 = new TavoloDa2(g1, g2);
		    tavoli.Add(TavoloDa2);
		
	    }
	
	    private void generaTavoloDa3() 
        {
		    List<Giocatore> giocatori = Torneo.getListaGiocatori();

		    int i1; Giocatore g1;
		    int i2; Giocatore g2;
		    int i3; Giocatore g3;
		
		    bool compagni;
		    bool limiteAvversariSuperato = false; 
		    bool limiteTavoloSuperato = false; 
		
		    int timeout = 500;
		    int times = 0;
		
		    do {
			
			    do {
                    i1 = rnd.Next(0, giocatori.Count);
				    g1 = giocatori.ElementAt(i1);
			    } while (!isOkPerTavoloDa3(g1));
			
			
			    do {
				    do {
					    while ((i2 = rnd.Next(0, giocatori.Count)) == i1);
					    g2 = giocatori.ElementAt(i2);
				    } while (Torneo.RegolaSesso == ModalitaSesso.SessoUnico && g2.Sesso != g1.Sesso);
			    } while (!isOkPerTavoloDa3(g2));
			
			
			    do {
				    do {
					    do {
						    i3 = rnd.Next(0, giocatori.Count);
					    } while ((i3 == i1) || (i3 == i2));
					    g3 = giocatori.ElementAt(i3);
				    } while (Torneo.RegolaSesso == ModalitaSesso.SessoUnico && ((g3.Sesso != g1.Sesso) || (g3.Sesso != g2.Sesso)));
			    } while (!isOkPerTavoloDa3(g3));
			
			    compagni = ((Torneo.RegolaCompagni == ModalitaCompagni.Mai) || (Torneo.RegolaCompagni == ModalitaCompagni.SiCoppiaNoAvversario));
			    compagni = compagni && ((g1.Compagno == g2) || (g1.Compagno == g3) || (g2.Compagno == g1) || (g2.Compagno == g3) || (g3.Compagno == g1) || (g3.Compagno == g2));
			
			
			    // Torneo.LimiteRipetiAvversario<=0 vuol dire nessun limite
			    if ((Torneo.LimiteRipetiAvversario > 0) || (Torneo.LimiteRipetiTavolo > 0)) {
			
				    int usataVolteAvv12 = g1.GiocaControVolte(g2);
				    int usataVolteAvv13 = g1.GiocaControVolte(g3);
				    int usataVolteAvv21 = g2.GiocaControVolte(g1);
				    int usataVolteAvv23 = g2.GiocaControVolte(g3);
				    int usataVolteAvv31 = g3.GiocaControVolte(g1);
				    int usataVolteAvv32 = g3.GiocaControVolte(g2);

				    int usataVolteTav12 = g1.GiocaControVolte(g2) + g1.GiocaAssiemeVolte(g2);
				    int usataVolteTav13 = g1.GiocaControVolte(g3) + g1.GiocaAssiemeVolte(g3);
				    int usataVolteTav21 = g2.GiocaControVolte(g1) + g2.GiocaAssiemeVolte(g1);
				    int usataVolteTav23 = g2.GiocaControVolte(g3) + g2.GiocaAssiemeVolte(g3);
				    int usataVolteTav31 = g3.GiocaControVolte(g1) + g3.GiocaAssiemeVolte(g1);
				    int usataVolteTav32 = g3.GiocaControVolte(g2) + g3.GiocaAssiemeVolte(g2);
			
			
				    int limite = Torneo.LimiteRipetiAvversario;
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv12 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv13 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv21 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv23 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv31 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv32 >= limite));

				    limite = Torneo.LimiteRipetiTavolo;
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav12 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav13 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav21 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav23 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav31 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav32 >= limite));

			    }
			
			    if (compagni || limiteAvversariSuperato || limiteTavoloSuperato) {
                    if (onTavoloDa3NonValido != null)
                    {
                        TavoloDa3NonValidoEventArgs ea = new TavoloDa3NonValidoEventArgs();
                        ea.Compagni = compagni;
                        ea.LimiteAvversariSuperato = limiteAvversariSuperato;
                        ea.LimiteTavoloSuperato = limiteTavoloSuperato;
                        ea.Giocatore1 = g1;
                        ea.Giocatore2 = g2;
                        ea.Giocatore3 = g3;
                        onTavoloDa3NonValido(this, ea);
                    }
                    if (++times >= timeout)
                    {
					    Torneo.Ricomincia();
					    return;
				    }
			    }

		    } while(compagni || limiteAvversariSuperato || limiteTavoloSuperato);
		
		    Torneo.getListaGiocatoriInTavoloDa3().Add(g1);
		    Torneo.getListaGiocatoriInTavoloDa3().Add(g2);
		    Torneo.getListaGiocatoriInTavoloDa3().Add(g3);
		    g1.AggiungiAvversari(g2);
		    g1.AggiungiAvversari(g3);
		    g2.AggiungiAvversari(g1);
		    g2.AggiungiAvversari(g3);
		    g3.AggiungiAvversari(g1);
		    g3.AggiungiAvversari(g2);
		    TavoloDa3 = new TavoloDa3(g1, g2, g3);
		    tavoli.Add(TavoloDa3);
		
	    }
	
	
        //public void stampaListaCoppie() {
        //    for (int i=0; i < coppie.Count; i++) {
        //        Coppia c = coppie.ElementAt(i);
        //        Logger.println("Coppia " + (i + 1) + ":\t" + c.NomiCoppia);
        //    }
        //}
	
	    private void generaCoppie(List<Giocatore> esclusi)
        {
		    List<Giocatore> giocatori = new List<Giocatore>(); 
            foreach (Giocatore g in Torneo.getListaGiocatori())
            {
			    if (!esclusi.Contains(g)) giocatori.Add(g);
		    }
		
		    // Insieme di coppie usate in questo tentativo
		    List<Coppia> coppieTentativo = new List<Coppia>();

		    int cont = 0, max = 0, tot = 0, tentativi = 1;
		    while (true) {
			    cont++;
			    tot++;
			    int i1; Giocatore g1;
			
			    //do {
                    i1 = rnd.Next(0, giocatori.Count);
				    g1 = giocatori.ElementAt(i1);
			    //} while(esclusi.Contains(g1));
			
			    int i2; Giocatore g2;
			    //do {
				    do {
					    while ((i2 = rnd.Next(0, giocatori.Count)) == i1);
					    g2 = giocatori.ElementAt(i2);
				    } while ( false
					    || (Torneo.RegolaSesso == ModalitaSesso.MaschioConFemmina && g2.Sesso == g1.Sesso)
					    || ((Torneo.RegolaSesso == ModalitaSesso.MaschiVsFemmine || Torneo.RegolaSesso == ModalitaSesso.SessoUnico) && g2.Sesso != g1.Sesso)
						    );
			    //} while(esclusi.Contains(g2));
			
			
			    // Torneo.LimiteRipetiCoppia<=0 vuol dire nessun limite
			    if (Torneo.LimiteRipetiCoppia > 0 || Torneo.LimiteRipetiTavolo > 0) 
                {
				    bool usataTentativo = false;
				    foreach (Coppia c in coppieTentativo) {
					
					    usataTentativo = usataTentativo || (c.getGiocatore(1) == g1 && c.getGiocatore(2) == g2);
					    usataTentativo = usataTentativo || (c.getGiocatore(1) == g2 && c.getGiocatore(2) == g1);
					
					    if (usataTentativo) break;
				    }
				    if (!usataTentativo) coppieTentativo.Add(new Coppia(g1,g2));
			    }			
			
			    bool giaUsata = false;
			    bool compagni = false;
			
			    foreach (Coppia c in coppie) {
				
				    giaUsata = giaUsata || (c.getGiocatore(1) == g1);
				    giaUsata = giaUsata || (c.getGiocatore(1) == g2);
				    giaUsata = giaUsata || (c.getGiocatore(2) == g1);
				    giaUsata = giaUsata || (c.getGiocatore(2) == g2);
				
			    }
			
			    compagni = compagni || (g1.Compagno == g2); 
			    compagni = compagni || (g2.Compagno == g1); 
			
			    compagni = compagni && (Torneo.RegolaCompagni == ModalitaCompagni.Mai || Torneo.RegolaCompagni == ModalitaCompagni.SiAvversarioNoCoppia);
			
			    bool limiteCoppiaSuperato = false;
			    // Torneo.LimiteRipetiCoppia<=0 vuol dire nessun limite
			    if (Torneo.LimiteRipetiCoppia > 0 || Torneo.LimiteRipetiTavolo > 0) {
			
				    limiteCoppiaSuperato = ((g1.GiocaAssiemeVolte(g2) >= Torneo.LimiteRipetiCoppia) || (g2.GiocaAssiemeVolte(g1) >= Torneo.LimiteRipetiCoppia));
			    }
			
			    if ((!giaUsata) && (!compagni) && (!limiteCoppiaSuperato)) {

				    Coppia c = new Coppia(g1,g2);
                    if (onCoppiaValida != null) onCoppiaValida(this, new CoppiaValidaEventArgs(c));
				    coppie.Add(c);
				    max = Math.Max(cont, max);
				    cont = 0;

			    }
			    else {
                    if (onCoppiaNonValida != null)
                    {
                        CoppiaNonValidaEventArgs ea = new CoppiaNonValidaEventArgs();
                        ea.Giocatore1 = g1;
                        ea.Giocatore2 = g2;
                        ea.GiaUsata = giaUsata;
                        ea.Compagni = compagni;
                        ea.LimiteCoppiaSuperato = limiteCoppiaSuperato;
                        onCoppiaNonValida(this, ea);
                    }
				
				    bool tentativoFallito = false;
				    String messaggio = "";
				
				    if (coppie.Count >= (Math.Floor((double)giocatori.Count/2)-1) && compagni && !giaUsata) {
					    tentativoFallito = true;
					    messaggio = "Impossibile continuare. L'ultima coppia sono compagni";
				    }
				
				    if (coppie.Count >= (Math.Floor((double)giocatori.Count/2)-1) && limiteCoppiaSuperato && !giaUsata) {
					    tentativoFallito = true;
					    messaggio = "Impossibile continuare. L'ultima coppia è già stata usata in un'altra partita il numero massimo di volte consentito";
				    }
				
				    int n = Torneo.getListaGiocatori().Count;
				    if ( coppieTentativo.Count >= (n * (n-1) / 2) ) {
					    tentativoFallito = true;
					    messaggio = "Impossibile continuare. Tutte le altre coppie sono state provate senza successo.";
				    }
				
				    if (tentativoFallito) {
                        if (onTentativoFallito != null) onTentativoFallito(this, new TentativoCoppiaFallitoEventArgs(messaggio, tentativi));
                        
					    coppie.Clear();
					    cont=0; tot=0; max=0;
					    tentativi ++;
    //					if (verbose) Logger.println(tentativi);
					    coppieTentativo.Clear();

					    if (tentativi > 500) {
						    Torneo.Ricomincia();
						    Torneo.getListaPartite().Add(this);
						    tentativi = 1;
					    }
				    }
				    continue;
				
			    }			
			    if (coppie.Count >= Math.Floor(((double)giocatori.Count)/2)) 
				    break;

		    }

            Torneo.getListaCoppieUsate().AddRange(coppie);

            if (onGeneraCoppieCompletato != null)
            {
                GeneraCoppieCompletatoEventArgs ea = new GeneraCoppieCompletatoEventArgs();
                ea.Tentativi = tentativi;
                ea.CicliNonValidiConsecutivi = max;
                ea.CicliNonValidiTotali = tot;

                onGeneraCoppieCompletato(this, ea);
            }
		
	    }
	
	
	
	
	
	
	

        //public void stampaListaTavoli() 
        //{
        //    for (int i=0; i < tavoli.Count; i++) {
        //        ITavolo t = tavoli.ElementAt(i);
        //        Logger.println("Tavolo " + (i + 1) + ":\t" + t.getNomiGiocatori());
        //    }
        //}
	
	
	

	    public void generaTavoli() 
        {
		
		    List<Giocatore> giocatori = Torneo.getListaGiocatori();
		
		    int nGiocatori = giocatori.Count;
		    List<Giocatore> esclusi = new List<Giocatore>();;
		    switch (nGiocatori % 4) {
			
		    case 1:
			    generaTavoloDa2();
			    if (TavoloDa2 == null) return;
			    esclusi.Add(TavoloDa2.getGiocatore(1));
			    esclusi.Add(TavoloDa2.getGiocatore(2));
			    generaTavoloDa3();
			    if (TavoloDa3 == null) return;
			    esclusi.Add(TavoloDa3.getGiocatore(1));
			    esclusi.Add(TavoloDa3.getGiocatore(2));
			    esclusi.Add(TavoloDa3.getGiocatore(3));
			    break;
			
		    case 2:
			    generaTavoloDa2();
			    if (TavoloDa2 == null) return;
			    esclusi.Add(TavoloDa2.getGiocatore(1));
			    esclusi.Add(TavoloDa2.getGiocatore(2));
			    break;
			
		    case 3:
			    generaTavoloDa3();
			    if (TavoloDa3 == null) return;
			    esclusi.Add(TavoloDa3.getGiocatore(1));
			    esclusi.Add(TavoloDa3.getGiocatore(2));
			    esclusi.Add(TavoloDa3.getGiocatore(3));
			    break;
			
		    }
		
		    generaCoppie(esclusi);

		    List<ITavolo> tavoliUsati = Torneo.getListaTavoliUsati();
		
		    // Insieme di tavoli usati in questo tentativo
		    List<TavoloDa4> tavoliTentativo = new List<TavoloDa4>();

		    int cont = 0, max = 0, tot = 0, tentativi = 1;
		    while (true) {
			    cont++;
			    tot++;
			    int i1; Coppia c1;
			    i1 = rnd.Next(0, coppie.Count);
			    c1 = coppie.ElementAt(i1);
			    SessoGiocatore sesso1 = c1.getGiocatore(1).Sesso;
						
			    int i2; Coppia c2; SessoGiocatore sesso2;
			    do {
				    while ((i2 = rnd.Next(0, coppie.Count)) == i1);
				    c2 = coppie.ElementAt(i2);
				
				    sesso2 = c2.getGiocatore(1).Sesso;
			    } while ( false
					    || ((Torneo.RegolaSesso == ModalitaSesso.SessoUnico) && (sesso1 != sesso2))
					    || ((Torneo.RegolaSesso == ModalitaSesso.MaschiVsFemmine) && (sesso1 == sesso2))
					    );

			    if (Torneo.LimiteRipetiAvversario > 0 || Torneo.LimiteRipetiTavolo > 0) {
				
				    bool usataTentativo = false;
				    for (int j=0; j < tavoliTentativo.Count; j++) {
					
					    TavoloDa4 t = tavoliTentativo.ElementAt(j);
					    usataTentativo = usataTentativo || (t.getCoppia(1) == c1 && t.getCoppia(2) == c2);
					    usataTentativo = usataTentativo || (t.getCoppia(1) == c2 && t.getCoppia(2) == c1);
					
				    }
				    if (!usataTentativo) tavoliTentativo.Add(new TavoloDa4(c1,c2));
				
			    }
			
			    bool giaUsata = false;
			    bool compagni = false;
			
			    for (int j=0; j < tavoliDa4.Count; j++) {
				
				    TavoloDa4 t = tavoliDa4.ElementAt(j);
					
				    giaUsata = giaUsata || (t.getCoppia(1) == c1);
				    giaUsata = giaUsata || (t.getCoppia(1) == c2);
				    giaUsata = giaUsata || (t.getCoppia(2) == c1);
				    giaUsata = giaUsata || (t.getCoppia(2) == c2);
				
			    }
			
			    compagni = compagni || (c1.getGiocatore(1).Compagno == c2.getGiocatore(1)); 
			    compagni = compagni || (c1.getGiocatore(1).Compagno == c2.getGiocatore(2)); 
			    compagni = compagni || (c1.getGiocatore(2).Compagno == c2.getGiocatore(1)); 
			    compagni = compagni || (c1.getGiocatore(2).Compagno == c2.getGiocatore(2)); 

			    compagni = compagni && (Torneo.RegolaCompagni == ModalitaCompagni.Mai || Torneo.RegolaCompagni == ModalitaCompagni.SiCoppiaNoAvversario);
			
			
			    // Torneo.LimiteRipetiAvversario<=0 vuol dire nessun limite
			    bool limiteAvversariSuperato = false; 
			    bool limiteTavoloSuperato = false; 
			    if ((Torneo.LimiteRipetiAvversario > 0) || (Torneo.LimiteRipetiTavolo > 0)) {
			
				    int usataVolteAvv11 = c1.getGiocatore(1).GiocaControVolte(c2.getGiocatore(1));
				    int usataVolteAvv12 = c1.getGiocatore(1).GiocaControVolte(c2.getGiocatore(2));
				    int usataVolteAvv21 = c1.getGiocatore(2).GiocaControVolte(c2.getGiocatore(1));
				    int usataVolteAvv22 = c1.getGiocatore(2).GiocaControVolte(c2.getGiocatore(2));

				    int usataVolteTav11 = c1.getGiocatore(1).GiocaControVolte(c2.getGiocatore(1)) + c1.getGiocatore(1).GiocaAssiemeVolte(c2.getGiocatore(1));
				    int usataVolteTav12 = c1.getGiocatore(1).GiocaControVolte(c2.getGiocatore(2)) + c1.getGiocatore(1).GiocaAssiemeVolte(c2.getGiocatore(2));
				    int usataVolteTav21 = c1.getGiocatore(2).GiocaControVolte(c2.getGiocatore(1)) + c1.getGiocatore(2).GiocaAssiemeVolte(c2.getGiocatore(1));
				    int usataVolteTav22 = c1.getGiocatore(2).GiocaControVolte(c2.getGiocatore(2)) + c1.getGiocatore(2).GiocaAssiemeVolte(c2.getGiocatore(2));
			
			
				    int limite = Torneo.LimiteRipetiAvversario;
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv11 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv12 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv21 >= limite));
				    limiteAvversariSuperato = (limiteAvversariSuperato || (usataVolteAvv22 >= limite));

				    limite = Torneo.LimiteRipetiTavolo;
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav11 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav12 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav21 >= limite));
				    limiteTavoloSuperato = (limiteTavoloSuperato || (usataVolteTav22 >= limite));

			    }
			
			
			    if ((!giaUsata) && (!compagni) && (!limiteAvversariSuperato) && (!limiteTavoloSuperato)) {
				    TavoloDa4 t = new TavoloDa4(c1,c2);
                    if (onTavoloDa4Valido != null) onTavoloDa4Valido(this, new TavoloDa4ValidoEventArgs(t));
				    tavoliDa4.Add(t);
				    tavoli.Add(t);
				    max = Math.Max(cont, max);
				    cont = 0;
			    }

						
			    else {
                    if (onTavoloDa4NonValido != null)
                    {
                        TavoloDa4NonValidoEventArgs ea = new TavoloDa4NonValidoEventArgs();
                        ea.GiaUsata = giaUsata;
                        ea.Compagni = compagni;
                        ea.LimiteAvversariSuperato = limiteAvversariSuperato;
                        ea.LimiteTavoloSuperato = limiteTavoloSuperato;
                        ea.Coppia1 = c1;
                        ea.Coppia2 = c2;
                        onTavoloDa4NonValido(this, ea);
                    }
   			        				
								
				    bool tentativoFallito = false;
				    String messaggio = "";
				
				    if (tavoliDa4.Count >= (Math.Floor((double)coppie.Count/2)-1) && compagni && !giaUsata) {
					    tentativoFallito = true;
					    messaggio = "Impossibile continuare. L'ultimo tavolo contiene compagni";
				    }
				
				    if (tavoliDa4.Count >= (Math.Floor((double)coppie.Count/2)-1) && limiteAvversariSuperato && !giaUsata) {
					    tentativoFallito = true;
					    messaggio = "Impossibile continuare. Nell'ultimo tavolo ci sono due giocatori che sono già stati avversari il numero massimo di volte consentito";
				    }
				
				    if (tavoliDa4.Count >= (Math.Floor((double)coppie.Count/2)-1) && limiteTavoloSuperato && !giaUsata) {
					    tentativoFallito = true;
					    messaggio = "Impossibile continuare. Nell'ultimo tavolo ci sono due giocatori che sono già stati nello stesso tavolo il numero massimo di volte consentito";
				    }
				
				    int n = coppie.Count;
				    int combinazioni = (n * (n-1) / 2);
				    if ( tavoliTentativo.Count >= combinazioni ) {
					    tentativoFallito = true;
					    messaggio = "Impossibile continuare. Tutte le altre coppie sono state provate senza successo.";
				    }
				
				    if (tentativoFallito) {
                        if (onTentativoFallito != null) onTentativoFallito(this, new TentativoTavoloFallitoEventArgs(messaggio, tentativi));
					    
                        tavoli.Clear();
					    cont=0; tot=0; max=0;
					    tentativi ++;
					    tavoliTentativo.Clear();

					    if (tentativi >= 500) {
						    Torneo.Ricomincia();
						    break;
					    }
				    }
				    continue;
			    }
			
			    int numTotTavoli = (int) Math.Ceiling(((double)Torneo.getListaGiocatori().Count)/4);
			    if (tavoli.Count >= numTotTavoli) 
				    break;

		    }

		    for(int i=0; i<tavoli.Count; i++) {
			    if (tavoli.ElementAt(i).GetType() == typeof(TavoloDa4)) 
                {
				    TavoloDa4 t = (TavoloDa4)tavoli.ElementAt(i);
				
				    Coppia c1 = t.getCoppia(1);
				    Coppia c2 = t.getCoppia(2);
				
				    c1.getGiocatore(1).AggiungiAiCompagni(c1.getGiocatore(2));
				    c1.getGiocatore(2).AggiungiAiCompagni(c1.getGiocatore(1));
				    c2.getGiocatore(1).AggiungiAiCompagni(c2.getGiocatore(2));
				    c2.getGiocatore(2).AggiungiAiCompagni(c2.getGiocatore(1));
				
				    c1.getGiocatore(1).AggiungiAvversari(c2.getGiocatore(1));
				    c1.getGiocatore(1).AggiungiAvversari(c2.getGiocatore(2));
				    c1.getGiocatore(2).AggiungiAvversari(c2.getGiocatore(1));
				    c1.getGiocatore(2).AggiungiAvversari(c2.getGiocatore(2));
				    c2.getGiocatore(1).AggiungiAvversari(c1.getGiocatore(1));
				    c2.getGiocatore(1).AggiungiAvversari(c1.getGiocatore(2));
				    c2.getGiocatore(2).AggiungiAvversari(c1.getGiocatore(1));
				    c2.getGiocatore(2).AggiungiAvversari(c1.getGiocatore(2));
			    }
			    tavoliUsati.Add(tavoli.ElementAt(i));
		    }

            if (onGeneraTavoliCompletato != null)
            {
                GeneraTavoliCompletatoEventArgs ea = new GeneraTavoliCompletatoEventArgs();
                ea.Tentativi = tentativi;
                ea.CicliNonValidiConsecutivi = max;
                ea.CicliNonValidiTotali = tot;

                onGeneraTavoliCompletato(this, ea);
            }

	    }
	
	
    }




    public class CoppiaNonValidaEventArgs : EventArgs
    {
        public Giocatore Giocatore1 { get; set; }
        public Giocatore Giocatore2 { get; set; }
        public bool GiaUsata { get; set; }
        public bool Compagni { get; set; }
        public bool LimiteCoppiaSuperato { get; set; }
    }
    public class CoppiaValidaEventArgs : EventArgs
    {
        public Coppia Coppia { get; set; }
        public CoppiaValidaEventArgs(Coppia c)
        {
            this.Coppia = c;
        }
    }
    public abstract class TavoloNonValidoEventArgs : EventArgs
    {
        public bool GiaUsata { get; set; }
        public bool Compagni { get; set; }
        public bool LimiteAvversariSuperato { get; set; }
        public bool LimiteCoppiaSuperato { get; set; }
        public bool LimiteTavoloSuperato { get; set; }
    }
    public class TavoloDa2NonValidoEventArgs : TavoloNonValidoEventArgs
    {
        public Giocatore Giocatore1 { get; set; }
        public Giocatore Giocatore2 { get; set; }
    }
    public class TavoloDa3NonValidoEventArgs : TavoloNonValidoEventArgs
    {
        public Giocatore Giocatore1 { get; set; }
        public Giocatore Giocatore2 { get; set; }
        public Giocatore Giocatore3 { get; set; }
    }
    public class TavoloDa4NonValidoEventArgs : TavoloNonValidoEventArgs
    {
        public Coppia Coppia1 { get; set; }
        public Coppia Coppia2 { get; set; }
    }
    public class TavoloDa4ValidoEventArgs : EventArgs
    {
        public TavoloDa4 Tavolo { get; set; }
        public TavoloDa4ValidoEventArgs(TavoloDa4 t)
        {
            this.Tavolo = t;
        }
    }

    public abstract class TentativoFallitoEventArgs : EventArgs
    {
        public string Messaggio { get; set; }
        public int Tentativi { get; set; }

        public TentativoFallitoEventArgs(string messaggio, int tentativi)
        {
            this.Messaggio = messaggio;
            this.Tentativi = tentativi;
        }
    }
    public class TentativoCoppiaFallitoEventArgs : TentativoFallitoEventArgs
    {
        public TentativoCoppiaFallitoEventArgs(string messaggio, int tentativi) : base(messaggio, tentativi) { }
    }
    public class TentativoTavoloFallitoEventArgs : TentativoFallitoEventArgs
    {
        public TentativoTavoloFallitoEventArgs(string messaggio, int tentativi) : base(messaggio, tentativi) { }
    }

    public abstract class CicloCompletatoEventArgs : EventArgs
    {
        public int Tentativi { get; set; }
        public int CicliNonValidiConsecutivi { get; set; }
        public int CicliNonValidiTotali { get; set; }
    }
    public class GeneraCoppieCompletatoEventArgs : CicloCompletatoEventArgs
    {
    }
    public class GeneraTavoliCompletatoEventArgs : CicloCompletatoEventArgs
    {
    }

}
